import { keyBy, assign, pick, map } from 'lodash-es'
/**
 * 通用数组同步函数：以基准数组 a 为准，同步目标数组 b
 * @param a 基准数组（源数组，提供最新数据）
 * @param b 目标数组（需要被同步的数组）
 * @param config 同步配置
 * @param config.uniqueKey 唯一标识键（用于匹配数组项，如 'id'/'uid'）
 * @param config.syncProps 需要同步的属性列表（如 ['name', 'age']）
 * @returns 同步后的新数组（不修改原数组）
 */
export const syncArrays = <
    T extends Record<string, any>,
    U extends Record<string, any>
>(
    a: T[],
    b: U[],
    config: {
        uniqueKey: keyof T & keyof U // 唯一键必须同时存在于 T 和 U 中
        syncProps: Array<keyof T & keyof U> // 同步属性必须同时存在于 T 和 U 中
    }
): U[] => {
    const { uniqueKey, syncProps } = config

    // 1. 将 b 转为 { [唯一键值]: 元素 } 的映射表，优化查找效率（O(1)）
    const bMap = keyBy(b, uniqueKey)

    // 2. 以 a 为基准遍历，处理「新增」和「更新」
    const synced = map(a, (itemA) => {
        // 获取当前项的唯一标识值
        const uniqueValue = itemA[uniqueKey]
        // 查找 b 中对应的项
        const existingItem = bMap[uniqueValue]

        if (existingItem) {
            // 情况1：b 中存在该唯一标识 → 同步指定属性（保留 b 的其他属性）
            // 从 itemA 中提取需要同步的属性，覆盖到 existingItem 上
            const syncData = pick(itemA, syncProps)
            return assign({}, existingItem, syncData) as U
        } else {
            // 情况2：b 中不存在该唯一标识 → 从 a 复制项（只包含 a 中的属性）
            return { ...itemA } as unknown as U
        }
    })

    // 情况3：b 中独有的项（a 中无对应唯一标识）→ 不包含在结果中，即被删除
    return synced
}
